package scaladuct

import collection.mutable.Queue
import collection.mutable.ArrayStack
import collection.immutable.List
import hint.{HintsPrompt, HasHints, HintPage}

/**
 * <p>
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: Aug 29, 2010
 * Time: 5:25:21 PM
 */
@deprecated
abstract class CookieServer[X](firstPageNonDecorated: ConfigPage[X]) {
  private[this] lazy val firstPage = decoratePage(firstPageNonDecorated)
  private[this] lazy val pageStack: ArrayStack[ConfigPage[_]] = {
    val stack = new ArrayStack[ConfigPage[_]]()
    stack.push(firstPage)
    stack
  }
  private[this] lazy val questionStack: ArrayStack[Question] = new ArrayStack[Question]
  protected[this] lazy val messageQueue: Queue[MessageFromServer] = Queue(EditCookie(ConfigPageTO(firstPage, null), firstPage.getCookie, null))
  private[this] var nextProcessId = 0
  private[this] def computeNextProcessId() = {
    nextProcessId += 1
    nextProcessId
  }
  private[this] lazy val processStack: ArrayStack[ConfigProcess] = {
    val pstack = new ArrayStack[ConfigProcess]
    pstack.push(ConfigProcess(computeNextProcessId, null, firstPage.id, 0))
    pstack
  }

  def pullServerMessage(): Option[MessageFromServer] = {
    if (messageQueue.isEmpty)
      None
    else
      Some(messageQueue.dequeue)
  }

  def pendingServerMessage(): Option[MessageFromServer] = {
    if (messageQueue.isEmpty)
      None
    else
      Some(messageQueue.head)
  }

  def pendingConfigPage(): Option[ConfigPage[_]] = {
    if (pageStack.isEmpty)
      None
    else
      Some(pageStack.top)
  }

  def process() = processStack.top

  def processClientMessage(clientMessage: MessageFromClient) {

    def processEditedCookieFromClient(cookie: AnyRef, pageTO: ConfigPageTO, context: AnyRef): Unit = {
      handleEditedCookie(cookie, pageTO, context)
      pageStack.pop.consumeRawCookie(cookie) match {
        case NewStarter(starter) => {
          processStack.pop
          if (pageStack.isEmpty) {
            messageQueue.enqueue(ResultStarter[X](starter.asInstanceOf[Starter[X]], context))
          } else {
            val question: Question = questionStack.pop
            messageQueue.enqueue(AnswerStarter(starter, question, ConfigPageTO(pageStack), pageStack.top.getCookie, context))
          }
        }
        case NextPage(nextPage) => {
          val decorating = decoratePage(nextPage)
          pageStack.push(decorating)
          messageQueue.enqueue(EditCookie(ConfigPageTO(pageStack), decorating.getCookie, context))
        }
      }
    }

    clientMessage match {
      case EditedCookie(cookie, pageTO, context) => {
        processEditedCookieFromClient(cookie, pageTO, context)
      }
      case Question(level, subject, context) => {
        handleQuestion(level, subject) match {
          case Some(questionPage) => {
            val decorating = decorateHintPage(questionPage)
            pageStack.push(decorating)
            questionStack.push(clientMessage.asInstanceOf[Question])

            messageQueue.enqueue(EditCookie(ConfigPageTO(pageStack), decorating.getCookie, context))
            processStack.push(ConfigProcess(computeNextProcessId, processStack.top, decorating.id, processStack.top.level + 1))
          }
          case None => {
            messageQueue.enqueue(NoAnswer(clientMessage.asInstanceOf[Question], ConfigPageTO(pageStack), pageStack.top.getCookie, context))
          }
        }
      }
      case Escape(context) => {
        handleInterrupt
        pageStack.pop.cancel
        processStack.pop
        if (pageStack.isEmpty) {
          messageQueue.enqueue(NoResult(context))
        } else {
          val question: Question = questionStack.pop
          messageQueue.enqueue(NoAnswer(question, ConfigPageTO(pageStack), pageStack.top.getCookie, context))
        }
      }
    }
  }

  protected def decoratePage[X](decorated: ConfigPage[X]): ConfigPage[X] = decorated

  protected def decorateHintPage[X](decorated: HintPage[X]): HintPage[X] = decorated

  protected def handleEditedCookie(cookie: AnyRef, pageTO: ConfigPageTO, context: AnyRef) {}

  protected def handleInterrupt() {}

  protected def handleQuestion(level: Int, subject: String): Option[HintPage[_]] = {
    pendingConfigPage match {
      case None => None
      case Some(page) => {
        page.extension(classOf[HasHints[AnyRef]]) match {
          case None => None
          case Some(withHints) => Some(HintsPrompt[AnyRef](withHints, level, subject, null, "QuestionPrompt"))
        }
      }
    }
  }

}

object CookieServer {
  def apply[X](page: ConfigPage[X]): CookieServer[X] = new CookieServer[X](page) {}
  def configurator[X](page: ConfigPage[X]): Configurator[X] =
    new CookieServer[X](page) with Configurator[X]
}

case class ConfigProcess(id: Long, parent: ConfigProcess, name: String, level: Int)

trait ListCookie[T] extends ScalaObject {var value: List[T]}
object ListCookie {
  def apply[T](v: List[T]): ListCookie[T] = {
    new ListCookie[T] {
      var value = v
    }
  }
}

trait Configurator[X] extends CookieServer[X] {
  def configure(processor: (MessageFromServer) => Option[MessageFromClient]) {
    pullServerMessage match {
      case None => // the end
      case Some(serverMessage) => {
        processor(serverMessage) match {
          case None =>
          case Some(clientMessage) => processClientMessage(clientMessage)
        }
        configure(processor) // a tail recursion 
      }
    }
  }

}

object Configurator {
  def apply[X](page: ConfigPage[X]): Configurator[X] = 
    new CookieServer[X](page) with Configurator[X]
}

trait ServerMessageProcessor extends Function[MessageFromServer, Option[MessageFromClient]] {
  def apply(message: MessageFromServer) = {
    processServerMessage(message)
  }

  def processServerMessage(serverMessage: MessageFromServer): Option[MessageFromClient]
}